﻿-- Author      : Thorwald Odin
-- Create Date : 12/7/2013 1:49:47 PM
local _, addon = ...;

local L = addon.Locale;

local Recycler = LibStub('LibRecycler-1.0');

do -- Config data
	local defaults = {
		profile = {
			Enabled = true,
			ConfigMode = true,
			DebugWatch = {
				error = true,
				warning = true,
				notice = true,
				Timestamp = true,
			},
			FilterMode = 'Increment',
			Delayed = {
				Threshold = 5,
				AllBags = true,
			},
			ParseBag = {
				true, true, true, true, true,
			},
			NotifyIgnore = true,
			FilterDelay = 0.5,
			Filters = {
			},
			MinimapIcon = {
			},
		},
	};
	
	local filterDefaults = {
		Enabled = false,
		Weight = 1,
		Action = 'Keep',
		Type = 'ItemType',
	};
	
	function addon:AddFilterVariables(vars)
		for k, v in pairs(vars) do
			filterDefaults[k] = v;
		end
	end
	
	function addon:AddDefaultVariables(vars)
		for k, v in pairs(vars) do
			defaults.profile[k] = v;
		end
	end
	
	addon.Filter = {};
	
	do -- Filter data
		local Filter = addon.Filter;
		
		Filter.ConfigFunctions = {
			NewFilter = function(info)
				table.insert(addon.db.Filters, addon:TableCopy_Shallow(filterDefaults));
				addon:UpdateFilterList();
			end,
			DeleteFilter = function(info)
				table.remove(addon.db.Filters, info.arg.key);
				addon:UpdateFilterList();
			end,
			GetNameFromReason = function(info)
				return addon:Format('{1} if {2}', addon:GetFilterActionLabel(info.arg.db), addon:MakeFilterReason(info.arg.db));
			end,
			Set = function(info, value)
				info.arg.db[ info[#info] ] = value;
				Filter.ConfigFunctions.UpdateOrderDesc(info);
			end,
			Get = function(info)
				return info.arg.db[ info[#info] ];
			end,
			UpdateOrderDesc = function(info)
				local t = addon.Options.args.Filters.args.Options.args.MainFrame.args.List.args[info.arg.name].args.Desc;
				t.name = Filter.ConfigFunctions.GetNameFromReason(info);
			end,
			MoveUp = function(info)
				local db = info.arg.db;
				db.Weight = min(100, db.Weight + 1);
				addon:UpdateFilterList();
			end,
			MoveDown = function(info)
				local db = info.arg.db;
				db.Weight = max(1, db.Weight - 1);
				addon:UpdateFilterList();
			end,
			GetFilterTypes = function(info)
				addon:UpdateConfigFilterTypes();
				return addon.Filter.ConfigFilterTypes;
			end,
			GetActions = function(info)
				addon:UpdateConfigFilterActions();
				return addon.Filter.ConfigFilterActions;
			end,
		};
		
		Filter.NewConfigTable = function()
			local t = {
				type = 'group',
				get = addon.Filter.ConfigFunctions.Get,
				set = addon.Filter.ConfigFunctions.Set,
				arg = {
				},
				args = {
					Enabled = {
						type = 'toggle',
						order = 1,
						name = L['Enable'],
						desc = L['Enable this filter'],
					},
					Action = {
						type = 'select',
						order = 3,
						name = L['Action'],
						desc = L['Action to take on items that match this filter.'],
						values = addon.Filter.ConfigFunctions.GetActions,
					},
					Weight = {
						type = 'range',
						order = 2,
						name = L['Priority'],
						desc = L['How important this filter is. Larger values mean that this filter is more important.'],
						min = 1,
						max = 100,
						step = 1,
					},
					Type = {
						type = 'select',
						order = 4,
						name = L['Filter criteria type'],
						desc = L['Type of data used to match items to this filter.'],
						values = addon.Filter.ConfigFunctions.GetFilterTypes,
					},
				},
			};
			
			for k, v in next, addon:GetFilterTypeOptions() do
				t.args[k] = v;
			end
			
			for k, v in next, addon:GetValueMethodOptions() do
				t.args.ItemValue.args[k] = v;
			end
			
			function populateArgs(t)
				for k, v in pairs(t.args) do
					v.arg = t.arg;
					if v.type == 'group' then
						v.guiInline = true;
						if type(v.args) == 'table' then
							populateArgs(v);
						end
					end
				end
			end
			populateArgs(t);
			
			return t;
		end
		
		Filter.NewOrderTable = function()
			local t = {
				type = 'group',
				get = Filter.ConfigFunctions.Get,
				set = Filter.ConfigFunctions.Set,
				arg = {
				},
				args = {
					Enabled = {
						type = 'toggle',
						order = 1,
						name = L['Enable'],
						desc = L['Enable this filter.'],
						width = 'half',
					},
					Desc = {
						type = 'description',
						order = 10,
						name = addon.Filter.ConfigFunctions.GetNameFromReason,
					},
					Delete = {
						type = 'execute',
						order = 2,
						name = L['Delete'],
						desc = L['Delete this filter.'],
						func = addon.Filter.ConfigFunctions.DeleteFilter,
						width = 'half',
					},
					MoveUp = {
						type = 'execute',
						order = 3,
						name = L['Up'],
						desc = L['Increase the priority of this filter.'],
						func = addon.Filter.ConfigFunctions.MoveUp,
						width = 'half',
					},
					MoveDown = {
						type = 'execute',
						order = 4,
						name = L['Down'],
						desc = L['Decrease the priority of this filter.'],
						func = addon.Filter.ConfigFunctions.MoveDown,
						width = 'half',
					},
				},
			};
			for k, v in pairs(t.args) do
				v.arg = t.arg;
			end
			return t;
		end
		
		Filter.ConfigGroup = Recycler:NewRecycler('FilterConfigGroup', Filter.NewConfigTable, nil);
		Filter.OrderGroup = Recycler:NewRecycler('FilterOrderGroup', Filter.NewOrderTable, nil);
		
		Filter.AcquireConfigGroup = function(name, db, order)
			local t = addon.Filter.ConfigGroup:Acquire();
			t.name = name;
			t.order = order + 1;
			t.arg.db = db;
			t.arg.key = order;
			t.arg.name = name;
			return t;
		end
		
		Filter.AcquireOrderGroup = function(name, db, order)
			local t = addon.Filter.OrderGroup:Acquire();
			t.name = name;
			t.order = order + 1;
			t.arg.db = db;
			t.arg.key = order;
			t.arg.name = name;
			t.args.Desc.name = Filter.ConfigFunctions.GetNameFromReason;
			return t;
		end
		
	end

	function addon:SetupConfig()
		self.Database = LibStub("AceDB-3.0"):New("LootFilterDB", defaults);
		self.Database.RegisterCallback(self, "OnProfileChanged", "UpdateProfile");
		self.Database.RegisterCallback(self, "OnProfileCopied", "UpdateProfile");
		self.Database.RegisterCallback(self, "OnProfileReset", "UpdateProfile");
		
		self.db = self.Database.profile;
		
		LibStub("AceConfigRegistry-3.0"):RegisterOptionsTable("LootFilter", self.Options);
		
		self.Options.args.Profiles = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.Database);
		
		for k, v in next, addon:GetFilterActionOptions() do
			addon.Options.args.Main.args.FilterActionOptions.args[k] = v;
			v.guiInline = true;
		end
	end

	function addon:ShowConfig()
		addon:UpdateFilterList();
		LibStub("AceConfigDialog-3.0"):Open("LootFilter");
	end

	function addon:UpdateProfile(event, database)
		self.db = database.profile;
		addon:UpdateLDB();
		addon:UpdateFilterList();
	end

	function addon:UpdateFilterList()
		local list = addon.Options.args.Filters.args.Options.args;
		local order = addon.Options.args.Filters.args.Options.args.MainFrame.args.List.args;
		for k, v in pairs(order) do
			addon.Filter.ConfigGroup:Release(list[k]);
			addon.Filter.OrderGroup:Release(v);
			list[k] = nil;
			order[k] = nil;
		end
		
		table.sort(addon.db.Filters, addon.Filter.SortFunctions.ByFilter);
		
		for i, v in pairs(addon.db.Filters) do
			local name = 'Filter ' .. i;
			list[name] = addon.Filter.AcquireConfigGroup(name, v, i);
			order[name] = addon.Filter.AcquireOrderGroup(name, v, i);
		end
	end
	
	addon.Options = {
		type = 'group',
		order = 1,
		name = L['LootFilter'],
		childGroups = 'tab',
		get = function(i)
			return addon.db[ i[#i] ];
		end,
		set = function(i, v)
			addon.db[ i[#i] ] = v;
		end,
		args = {
			Enabled = {
				type = 'toggle',
				order = 1,
				name = L['Enable'],
				desc = L['Enable filtering of looted items.'],
				width = 'half',
			},
			ConfigMode = {
				type = 'toggle',
				order = 2,
				name = L['Config mode'],
				desc = L['Item filtering continues as normal except that items will not be deleted. A message will be posted in the debug window and the chat frame when an action is blocked because of this option.\nThis is useful when configuring filters.\nThis option is enabled by default.'],
			},
			MinimapIcon = {
				type = 'toggle',
				order = 3,
				name = L['Show minimap icon'],
				desc = L['Show the LibDataBroker icon on the minimap'],
				get = function(i)
					return not addon.db.MinimapIcon.hide;
				end,
				set = function(i, v)
					addon.db.MinimapIcon.hide = not v;
					addon:UpdateLDB();
				end,
			},
			Colorblind = {
				type = 'toggle',
				order = 4,
				name = USE_COLORBLIND_MODE,
				desc = OPTION_TOOLTIP_USE_COLORBLIND_MODE,
				get = function(i)
					return ENABLE_COLORBLIND_MODE == '1';
				end,
				set = function(i, v)
					v = v and '1' or '0';
					ENABLE_COLORBLIND_MODE = v;
					SetCVar('colorblindMode', v);
					addon:UpdateFilterList();
				end
			},
			Main = {
				type = 'group',
				order = 5,
				name = L['Loot processing'],
				desc = L['Options that control how loot is processed.'],
				args = {
					FilterDelay = {
						type = 'range',
						order = 1,
						name = L['Processing delay'],
						desc = L['Number of milliseconds to wait after looting before items are processed.'],
						min = 0.1,
						max = 3.5,
						step = 0.05,
						bigStep = 0.1,
					},
					FilterMode = {
						type = 'select',
						order = 2,
						name = L['Filter modes'],
						desc = L['The method used to filter items.'],
						values = {
							Delayed = L['Delayed filtering'],
							Increment = L['Incremental filtering'],
							Demand = L['On-Demand filtering'],
						},
					},
					Bags = {
						type = 'multiselect',
						order = 3,
						name = L['Bags to filter'],
						desc = L['Bags that LootFilter will delete items from.'],
						get = function(i, k)
							return addon.db.ParseBag[k];
						end,
						set = function(i, k, v)
							addon.db.ParseBag[k] = v;
						end,
						values = {
							[1] = L['Main backpack'],
							[2] = L['First bag'],
							[3] = L['Second bag'],
							[4] = L['Third bag'],
							[5] = L['Fourth bag'],
						},
					},
					DelayedOptions = {
						type = 'group',
						order = 6,
						guiInline = true,
						name = L['Delayed filtering options'],
						get = function(i)
							return addon.db.Delayed[ i[#i] ];
						end,
						set = function(i, v)
							addon.db.Delayed[ i[#i] ] = v;
						end,
						hidden = function()
							return addon.db.FilterMode ~= 'Delayed';
						end,
						args = {
							Threshold = {
								type = 'range',
								order = 1,
								name = L['Filtering threshold'],
								desc = L['Number of available bag slots to maintain.'],
								min = 1,
								max = 40,
								step =  1,
							},
							AllBags = {
								type = 'toggle',
								order = 2,
								name = L['Count all bags'],
								desc = L['Count available bag space from bags that are not filtered.'],
							},
						},
					},
					FilterActionOptions = {
						type = 'group',
						guiInline = true,
						name = L['Filter action options'],
						order = 10,
						args = {
						},
					},
				},
			},
			Filters = {
				type = 'group',
				order = 6,
				name = L['Filters'],
				desc = '',
				args = {
					Options = {
						type = 'group',
						order = 1,
						name = L['Filter options'],
						childGroups = 'tree',
						args = {
							MainFrame = {
								type = 'group',
								order = 1,
								name = '',
								guiInline = true,
								args = {
									New = {
										type = 'execute',
										order = 1,
										name = L['New filter'],
										desc = L['Create a new filter a minimum priority.'],
										func = addon.Filter.ConfigFunctions.NewFilter,
									},
									List = {
										type = 'group',
										order = 2,
										name = L['Filter order'],
										args = {
										},
										hidden = function(info)
											return #(addon.db.Filters) == 0;
										end,
									},
									Desc = {
										type = 'description',
										order = 3,
										name = L['You do not have any filters on this profile.'],
										hidden = function(info)
											return #(addon.db.Filters) ~= 0;
										end,
									},
								},
							},
						},
					},
				},
			},
			DebugWatch = {
				type = 'group',
				order = 7,
				name = L['Debug window'],
				get = function(i)
					return addon.db.DebugWatch[ i[#i] ];
				end,
				set = function(i, v)
					addon.db.DebugWatch[ i[#i] ] = v;
				end,
				args = {
					Open = {
						type = 'execute',
						order = 1,
						name = L['Open debug window'],
						desc = L['Open the debug window'],
						func = function()
							addon:DisplayDebug();
						end,
					},
					Options = {
						type = 'group',
						order = 3,
						name = L['Events to show'],
						guiInline = true,
						args = {
							Timestamp = {
								type = 'toggle',
								order = 2,
								name = L['Show time stamps'],
								desc = L['Display time stamps on debug events.'],
							},
							error = {
								type = 'toggle',
								order = 3,
								name = L['Show errors'],
								desc = L['Display error events in the debug window.'],
							},
							warning = {
								type = 'toggle',
								order = 4,
								name = L['Show warnings'],
								desc = L['Display warning events in the debug window.'],
							},
							notice = {
								type = 'toggle',
								order = 5,
								name = L['Show notices'],
								desc = L['Display notice events in the debug window.'],
							},
						},
					},
				},
			},
		},
	};

end

do -- LDB/LDBIcon
	local ldb = LibStub("LibDataBroker-1.1");
	local ldbi = LibStub("LibDBIcon-1.0");

	local _ColorCodes = {
		'|cff00ff00', -- 1
		'|cffff0000', -- 2
		'|cffffff00', -- 3
		'|cff66ccff', -- 4
	};
	
	local _ColorCodes_ColorBlind = {
		'',
		'',
		'',
		'',
	};
	
	local _Text_Prefetch = {
		L['Enabled'],
		L['Disabled'],
	};

	local ldbObject = {
		type = 'launcher',
		label = 'LootFilter',
		icon = [[Interface\Icons\INV_Misc_EngGizmos_17]],
		tocname = 'LootFilter',
		OnTooltipShow = function(self)
			local colorCodes = _ColorCodes;
			if ENABLE_COLORBLIND_MODE == '1' then
				colorCodes = _ColorCodes_ColorBlind;
			end
			local enable, config = addon.db.Enabled and 1 or 2, addon.db.ConfigMode and 1 or 2;
			GameTooltip:ClearLines();
			GameTooltip:AddLine(addon:Format(L['LootFilter ({2}v{1}|r)'], addon.Version, colorCodes[4]));
			GameTooltip:AddLine(addon:Format(L['{1}Click|r: Toggle filtering (Currently: {2}{3}|r)'], colorCodes[3], colorCodes[enable], _Text_Prefetch[enable]));
			GameTooltip:AddLine(addon:Format(L['{1}Right-Click|r: Open options window'], colorCodes[3]))
			GameTooltip:AddLine(addon:Format(L['{1}Shift-Click|r: Toggle configuration mode (Currently: {2}{3}|r)'], colorCodes[3], colorCodes[config], _Text_Prefetch[config]));
		end,
		OnClick = function(self, button)
			if button == "LeftButton" then
				if IsShiftKeyDown() then
					addon.db.ConfigMode = not addon.db.ConfigMode;
				else
					addon.db.Enabled = not addon.db.Enabled;
				end
				if self.dataObject then
					self.dataObject.OnTooltipShow(GameTooltip);
				end
			elseif button == "RightButton" then
				if IsShiftKeyDown() then
					addon:DisplayDebug();
				else
					addon:ShowConfig();
				end
			end
		end,
	};

	function addon:SetupLDB()
		ldb:NewDataObject("LootFilter", ldbObject);
		ldbi:Register("LootFilter", ldbObject, addon.db.MinimapIcon);
	end

	function addon:UpdateLDB()
		ldbi:Refresh("LootFilter", addon.db.MinimapIcon);
	end
end


